package org.ddd.orderdemo.application.service;

//import jakarta.transaction.Transactional;
import org.ddd.orderdemo.application.pojo.cmd.OrderCreateCmd;
import org.ddd.orderdemo.application.pojo.query.OrderQuery;
import org.ddd.orderdemo.domain.infra.mq.OrderMessageProducer;
import org.ddd.orderdemo.domain.infra.repository.IDeliveryAddressRepository;
import org.ddd.orderdemo.domain.infra.repository.IOrderRepository;
import org.ddd.orderdemo.domain.infra.repository.IUserRepository;
import org.ddd.orderdemo.domain.model.order.DeliveryAddress;
import org.ddd.orderdemo.domain.model.order.Order;
import org.ddd.orderdemo.domain.model.order.OrderEventTypeEnum;
import org.ddd.orderdemo.domain.model.order.OrderItem;
import org.ddd.orderdemo.domain.model.product.Product;
import org.ddd.orderdemo.domain.model.user.User;
import org.ddd.orderdemo.domain.service.OrderDomainService;
import org.ddd.orderdemo.shared.exception.DemoBusinessException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.UUID;

@Service
public class OrderService {

    @Autowired
    private OrderDomainService orderDomainService;


    private IUserRepository userRepository;

    private IDeliveryAddressRepository deliveryAddressRepository;

    private IOrderRepository orderRepository;

    @Autowired
    private OrderMessageProducer orderMessageProducer;

    /***
     * 代码解释：
     * 应用服务层是很轻量的，它不做任何业务逻辑的处理，通过协调实体和资源库来达成业务结果，
     * 而具体的业务逻辑在聚合根中实现。
     *
     * 因为有跨多个子域的操作，order、product、OrderItem等，且使用了外部服务（商品上
     * 下文和调度上下文），所以我们使用了orderDomainService领域服务
     *
     *
     * 应用服务层统一返回的是领域对象，由用户接口层决定转为什么样的模型（因为用户界面层
     * 可能有多个，对应着不同的客户端，不同的客户端锁需要的数据模型可能不同），从架构层
     * 面限制模型滥用和模型滥转
     *
     * @param cmd
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public Order createOrder(OrderCreateCmd cmd) {
        String orderNo = UUID.randomUUID().toString();
        //从资源库获取用户
        Optional<User> userOptional = userRepository.findById(cmd.getUserId());
        User user = userOptional.orElseThrow(() -> new DemoBusinessException("用户不存在"));

        //把参数转换为领域模型,可以定义convertor来进行转换
        List<OrderItem> orderItemList = makeOrderItems(cmd.getProductItems(), orderNo);
        //商品域-检查库存，product和OrderItem属于两个域,且使用了外部product服务,所以使用领域服务
        orderDomainService.checkInventoryAndAssembleOrderItems(orderItemList);

        //配送地址
        Optional<DeliveryAddress> deliveryInfoOptional = deliveryAddressRepository.findById(cmd.getDeliveryAddressId());
        DeliveryAddress deliveryAddress = deliveryInfoOptional.orElseThrow(() -> new DemoBusinessException("配送信息不存在"));

        //创建订单,最好的方式是使用工厂
        Order order = Order.create(orderNo, deliveryAddress, orderItemList, user.getUserId());
        //调度域-锁定库存,用到了远程服务,所以放到了领域服务
        orderDomainService.lockInventory(order);

        //创建订单
        orderRepository.createOrder(order);
        //发布订单创建事件
        orderMessageProducer.publish(order, OrderEventTypeEnum.INIT);
        //返回领域模型,由用户界面层决定转为什么样的模型, 从架构层面限制模型滥用和模型滥转
        return order;
    }


    private List<OrderItem> makeOrderItems(List<Product> productItems, String orderNo) {
        return new ArrayList<>();
    }

    public Optional<Order> findById(Long orderId) {
        return null;
    }


    public Order query(OrderQuery orderQuery) {
        return null;
    }

    public List<Order> getAllOrders() {
        return null;
    }

    public void updateStatus(Long id, Integer status) {

    }
}
